<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script>
        // 上下文调用方式，有3中，call、apply、bind
        function f1() {
            console.log(this)
        }

        // call方法的第一个参数决定了函数内部this的值
        f1.call([1, 3, 5]); // [1, 3, 5]
        f1.call({name: "张三", age: 18}); // {name: "张三", age: 18}
        f1.call(1); // Number {1}
        f1.call("1") // String {"1"}
        f1.call(false) // Boolean {false}
        f1.call(null) // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
        f1.call(undefined) // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}

        /*
            总结：
                call方法的第一个参数：
                1、如果是一个对象类型，那么函数内部的this指向该对象
                2、如果是null或者undefined类型，那么函数内部的this指向window
                3、如果是数字，函数内部的this指向Number()构造函数的实例
                    1 --> new Number(1)
                4、如果是字符串，函数内部的this指向String()构造函数的实例
                    "1" --> new String("1")
                5、如果是布尔值，函数内部的this指向Boolean()构造函数的实例
                    false --> new Boolean(false)
        */

        // 上述代码可以使用apply方法替代
        f1.apply([1, 3, 5]); // [1, 3, 5]
        f1.apply({name: "张三", age: 18}); // {name: "张三", age: 18}
        f1.apply(1); // Number {1}
        f1.apply("1") // String {"1"}
        f1.apply(false) // Boolean {false}
        f1.apply(null) // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
        f1.apply(undefined) // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
    
        /*
            call和apply的异同：传值方式不同
                使用call函数，第一个参数是this指向，其他参数一次排开
                    call(this, a, b, c)
                使用apply函数，第一个参数是this指向，其他参数一次放在一个数组中作为第二个参数传递
                    apply(this, [a, b, c])

        */
    </script>
</body>
</html>